package com.dongbao.action;

import com.dongbao.module.ScanResult;
import com.dongbao.utils.IDEAUtil;
import com.dongbao.utils.ToolUtils;
import com.dongbao.utils.ToolWindowUtil;
import com.dongbao.window.DHGLangWindow;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.file.PsiJavaDirectoryImpl;
import com.intellij.psi.impl.source.PsiEnumConstantImpl;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.impl.source.javadoc.PsiDocCommentImpl;
import com.intellij.psi.impl.source.tree.PsiCommentImpl;
import com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiClassUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.indices.MavenClassSearcher;
import org.jetbrains.idea.maven.model.MavenConstants;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jsoup.Jsoup;
import org.jsoup.helper.StringUtil;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @auto Wang
 * @NotLangScan
 * */
public class ScanLangAction extends AnAction {

    private List<ScanResult> results = new ArrayList<>();

    @Override
    public void actionPerformed(AnActionEvent e) {
        //判断区分当前是选择的全模块还是单个文件
        /* 调用保存方法保存文件 */
        results.clear();
        FileDocumentManager.getInstance().saveAllDocuments();
        ProgressManager.getInstance().run(new Task.Backgroundable(e.getProject(), e.getPresentation().getText(), false) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                ApplicationManager.getApplication().runReadAction(
                        () -> {
                            runScan(e,indicator);
                        }
                );
            }
        });
    }

    private void runScan(AnActionEvent e,ProgressIndicator indicator) {
        /* 获取当前选择的文件 */
        /* 读取该模块下面所有的文件 */
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
        String type = "java";
        if(module!=null){
            //执行Java代码扫描
            type = "java";
            excuJava(e,indicator);
        }else{
            //执行前端JS代码扫描
            type = "js";
            excuJS(e,indicator);
        }
        DHGLangWindow dhgToolWindow = ToolWindowUtil.getDHGToolWindow(e.getProject());
        Object[][] rowData = new Object[results.size()][];
        if(type.equals("java")){
            for(int i = 0; i < results.size(); i++){
                try{
                    rowData[i] = new Object[]{
                            (i+1),
                            results.get(i).getModule().getName(),
                            results.get(i).getPsiClass().getName(),
                            results.get(i).getPsiClass().getName(),
                            results.get(i).getType().getCanonicalText(),
                            results.get(i).getCodeContent()
                    };
                }catch (Exception ex){
                    ex.printStackTrace();
                }

            }
        }else{
            for(int i = 0; i < results.size(); i++){
                try{
                    rowData[i] = new Object[]{
                            (i+1),
                            results.get(i).getClassName(),
                            null,
                            null,
                            null,
                            results.get(i).getCodeContent()
                    };
                }catch (Exception ex){
                    ex.printStackTrace();
                }

            }
        }
        dhgToolWindow.referTableData(rowData,results);

    }

    /**
     * 开始执行JS扫描
     * */
    private void excuJS(AnActionEvent e,ProgressIndicator indicator){
        Collection<VirtualFile> moduleJavaFile = FilenameIndex.getAllFilesByExt(e.getProject(), "vue", GlobalSearchScope.allScope(e.getProject()));
//        Collection<VirtualFile> moduleJavaFile = FilenameIndex.getVirtualFilesByName("dbReport.vue", GlobalSearchScope.allScope(e.getProject()));
        //遍历所有文件开始检测所欲言
        indicator.setText("开始检测前端JS多语言信息");
        int i = 0;
        for(VirtualFile virtualFile:moduleJavaFile){
            i++;
            indicator.setText(String.format("正在扫描文件%s/%s",i,moduleJavaFile.size()));
            runScanJs(e,indicator,virtualFile);
        }
    }

    private void runScanJs(AnActionEvent e,ProgressIndicator indicator,VirtualFile virtualFile){
        PsiFile file = PsiManager.getInstance(e.getProject()).findFile(virtualFile);
        Document document = Jsoup.parse(file.getText());
        Element body = document.body();
        //开始解析子节点
        //解析HTML标签
//        List<Node> nodes1 = body.childNodes();
        List<Node> nodes = body.childNodes();
        for(int i =0 ;i<nodes.size();i++){
            excuHtmlElement(e,indicator,virtualFile,nodes.get(i));
        }

//            //解析JS
//            List<Element> elements = body.getElementsByTag("script");
//        for(Element element:elements){
//            String lang = element.attr("lang");
//            if(lang!=null){
//                String code = element.html();
//                ScanResult result = new ScanResult();
//                result.setLang(lang);
//                result.setCode(code);
//                results.add(result);
//            }
//        }
        indicator.setText("检测前端JS多语言信息完成");
    }

    private void excuHtmlElement(AnActionEvent e,ProgressIndicator indicator,VirtualFile virtualFile,Node allElement){
        if(allElement.childNodeSize()>0){
            //递归解析子节点
            List<Node> nodes = allElement.childNodes();
            for(Node elements:nodes){
                excuHtmlElement(e,indicator,virtualFile,elements);
            }
        }else{
            //判断是否存在中文 和 是否是注释行
            if(ToolUtils.isContainChinese(allElement.outerHtml()) && !ToolUtils.isHTMLCommon(allElement.outerHtml())){
                if(!allElement.outerHtml().contains("export default")){
                    //验证是否是注释信息
                    int lineAndColumn = 0;
                    try {
                        List<String> rowTexts = FileUtil.loadLines(virtualFile.getPath());
                        for(String rowText:rowTexts){
                            if(rowText.indexOf(allElement.outerHtml())!=-1){
                                lineAndColumn = rowTexts.indexOf(allElement.outerHtml());
                            }
                        }
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    PsiFile file = PsiManager.getInstance(e.getProject()).findFile(virtualFile);
                    ScanResult scanResult = new ScanResult();
                    scanResult.setClassName(virtualFile.getPath());
                    scanResult.setPsiClass(null);
                    scanResult.setType(null);
                    scanResult.setLineNumber(lineAndColumn);
                    scanResult.setCodeContent(allElement.outerHtml());
                    scanResult.setModule(null);
                    scanResult.setVirtualFile(virtualFile);
                    results.add(scanResult);
                }else{
                    //js代码解析
                    String jsContent = allElement.outerHtml();
                    System.out.println("6666");
                    String chineContent = jsContent.replaceAll("[^\u4E00-\u9FA5]", " ");
                    String[] chineSubs = chineContent.split(" ");
                    for(String chineSub:chineSubs){
                        if(StringUtil.isBlank(chineSub)){
                            continue;
                        }
                        ScanResult scanResult = new ScanResult();
                        scanResult.setClassName(virtualFile.getPath());
                        scanResult.setPsiClass(null);
                        scanResult.setType(null);
                        scanResult.setLineNumber(0);
                        scanResult.setCodeContent(chineSub);
                        scanResult.setModule(null);
                        scanResult.setVirtualFile(virtualFile);
                        results.add(scanResult);
                    }



//                    Pattern patten = Pattern.compile("[\u4e00-\u9fa5]");//编译正则表达式
//                    Matcher matcher = patten.matcher(jsContent);// 指定要匹配的字符串
//
//                    List<String> matchStrs = new ArrayList<>();
//
//                    while (matcher.find()) { //此处find（）每次被调用后，会偏移到下一个匹配
//                        matchStrs.add(matcher.group());//获取当前匹配的值
//                    }
//
//                    for (int i = 0; i < matchStrs.size(); i++) {
//                        PsiFile file = PsiManager.getInstance(e.getProject()).findFile(virtualFile);
//                        ScanResult scanResult = new ScanResult();
//                        scanResult.setClassName(virtualFile.getPath());
//                        scanResult.setPsiClass(null);
//                        scanResult.setType(null);
//                        scanResult.setLineNumber(0);
//                        scanResult.setCodeContent(matchStrs.get(i));
//                        scanResult.setModule(null);
//                        scanResult.setVirtualFile(virtualFile);
//                        results.add(scanResult);
//                    }
                }
            }
        }
//        System.out.println(6666);
    }

    /**
     * 开始执行Java扫描
     * */
    private void excuJava(AnActionEvent e,ProgressIndicator indicator){
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
        String moduleRootPath = ((PsiJavaDirectoryImpl)e.getData(LangDataKeys.PSI_ELEMENT_ARRAY)[0]).getVirtualFile().getPath();
        VirtualFile parentPom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(moduleRootPath, MavenConstants.POM_XML));
        MavenProject project = MavenProjectsManager.getInstance(e.getProject()).findProject(parentPom);
        List<VirtualFile> existingModuleFiles = project.getExistingModuleFiles();

        /* 判断选择的是不是子模块 */
        UUID uuid = UUID.randomUUID();
        List<String> cacheFiles = new ArrayList<String>();
        if(existingModuleFiles.isEmpty()){
            /* 根模块 */
            Collection<VirtualFile> moduleJavaFile = FilenameIndex.getAllFilesByExt(e.getProject(), "java", GlobalSearchScope.moduleScope(module));
            fileLangDetection(e,indicator,moduleJavaFile,module);
        }else{
            /* 遍历所有子模块 */
            for(VirtualFile childModule:existingModuleFiles){
                VirtualFile childPom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(childModule.getParent().getPath(), MavenConstants.POM_XML));
                MavenProject childProject = MavenProjectsManager.getInstance(e.getProject()).findProject(childPom);
                Module moduleForFile = ProjectFileIndex.getInstance(e.getProject()).getModuleForFile(childModule.getCanonicalFile());
                Collection<VirtualFile> moduleJavaFile = FilenameIndex.getAllFilesByExt(e.getProject(), "java", GlobalSearchScope.moduleScope(moduleForFile));
                fileLangDetection(e,indicator,moduleJavaFile,module);
            }
        }

    }

    /**
     * 开始遍历文件内容执行
     * */
    private void fileLangDetection(AnActionEvent e,ProgressIndicator indicator,Collection<VirtualFile> moduleJavaFile,Module module){
        //遍历文件
        for(VirtualFile file:moduleJavaFile){
            PsiFile classFile = PsiManager.getInstance(e.getProject()).findFile(file);
            for(int i=0;i<classFile.getChildren().length;i++){
                if(classFile.getChildren()[i] instanceof PsiClass){
                    PsiClass psiClass = (PsiClass)classFile.getChildren()[i];
                    //判断doc存不存在免死注解
                    PsiDocComment docComment = psiClass.getDocComment();
                    if(docComment!=null && psiClass.getDocComment().findTagByName("NotLangScan")!=null){
                        //存在doc文档,并且doc文档中存在 NotLangScan 标签,则直接下一循环
                       continue;
                    }else{
                        classLangDetection(e,indicator,file,psiClass,module);
                    }

                }
            }
        }
    }

    /**
     * 解析文件的class
     * */
    private void classLangDetection(AnActionEvent e,ProgressIndicator indicator,VirtualFile file,PsiClass curClass,Module module){
        //检查生成变量中是否存在中文
        PsiField[] fields = curClass.getFields();
        for(PsiField field:fields){
            fieldLangDetection(curClass,field,module);
        }

        //遍历类中所有的方法
        PsiMethod[] methods = curClass.getMethods();
        for(PsiMethod method:methods){
//            System.out.println("method:"+method.getName());
            IDEAUtil.chindPsiRow(method,method.getSourceElement(),item->{
//                 System.out.println("item:"+item);
                 if(ToolUtils.isContainChinese(item.getText())){
                     int lineAndColumn = IDEAUtil.getLineAndColumn(curClass, item);
                     ScanResult scanResult = new ScanResult();
                     scanResult.setClassName(curClass.getName());
                     scanResult.setPsiClass(curClass);
                     scanResult.setType(method.getReturnType());
                     scanResult.setLineNumber(lineAndColumn);
                     scanResult.setCodeContent(item.getText());
                     scanResult.setModule(module);
                     results.add(scanResult);
                 }
            });
        }
//        System.out.println(6666);
    }
    
    /**
     * 解析声明字段
     * */
    private void fieldLangDetection(PsiClass curClass,PsiField field,Module module){
        List<PsiElement> sourceElements = new ArrayList<>();
        StringBuilder elementText = new StringBuilder();
        if(field instanceof PsiEnumConstantImpl){
            //对于枚举类型的不进行多语言检测
            return ;
        }
        for(PsiElement element:field.getChildren()){
            if(element instanceof PsiDocCommentImpl || element instanceof PsiCommentImpl || element instanceof PsiModifierList){                //是注释信息,不管
                continue;
            }
            sourceElements.add(element);
            elementText.append(element.getText());
        }
        if(ToolUtils.isContainChinese(elementText.toString())){
//            System.out.println(" class: " + curClass.getName() + " field:" + field.getName());
            //存在中文,记录在案
            int lineAndColumn = IDEAUtil.getLineAndColumn(curClass, field);
            ScanResult scanResult = new ScanResult();
            scanResult.setClassName(curClass.getName());
            scanResult.setPsiClass(curClass);
            scanResult.setType(field.getType());
            scanResult.setLineNumber(lineAndColumn);
            scanResult.setCodeContent(elementText.toString());
            scanResult.setModule(module);
            results.add(scanResult);
        }
    }




    @Override
    public void update(@NotNull final AnActionEvent e) {
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
//        try{
//            boolean enable = module != null && AddFrameworkSupportDialog.isAvailable(module);
//            if (ActionPlaces.isPopupPlace(e.getPlace())) {
//                e.getPresentation().setVisible(enable);
//            }
//            else {
//                e.getPresentation().setEnabled(enable);
//            }
//        }catch (Exception exce){
//            e.getPresentation().setEnabled(true);
//        }
        e.getPresentation().setEnabled(true);
    }
}
